package tt.dz.egobus.servicemanager.base.controller;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import tt.dz.egobus.base.entity.BaseEntity;
import tt.dz.egobus.bean.CriteriaRestrictionsBuilder;
import tt.dz.egobus.bean.Pagination;
import tt.dz.egobus.servicemanager.base.service.ExtendBaseService;
import tt.dz.egobus.servicemanager.bean.EntityViewVo;
import tt.dz.egobus.servicemanager.bean.PagingationStart;
import tt.dz.egobus.servicemanager.core.exception.BusinessException;
import tt.dz.egobus.servicemanager.util.MapGetUtils;
import tt.dz.egobus.servicemanager.vo.JsonBack;

import javax.validation.Valid;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static tt.dz.egobus.servicemanager.bean.ServiceManagerCodeStatus.PARAM_ILLEGAL_ERROR;
import static tt.dz.egobus.servicemanager.bean.ServiceManagerCodeStatus.SYSTEM_CODE_ERROR;

/**
 * @author Anson
 * @date 17-3-15
 * @name 当前实体的简单操作集合
 * @since 1.0.1
 */
public abstract class EntityController<E extends BaseEntity, V extends EntityViewVo<E, V>, PK extends Serializable>
        extends CommonBinderController {

    private static final Logger LOGGER = LoggerFactory.getLogger(EntityController.class);

    protected abstract ExtendBaseService<E, PK> getSelfService();

    /**
     * @author Anson
     * @date 17-4-17
     * @name 创建创建一个新的view VO
     * @since 1.0.4
     */
    protected abstract V newViewVo();

    /**
     * @param param 带有查询匹配的key的参数集合
     * @author Anson
     * @date 17-3-14
     * @name 带有参数的查询结果集合
     * @see CriteriaRestrictionsBuilder
     * @since 1.0.1
     */
    @RequestMapping("/query")
    public JsonBack<List<V>> query(@RequestParam Map<String, Object> param) {
        JsonBack<List<V>> back = null;
        try {
            param = this.convertParams(param);
            if (param == null || param.isEmpty()) {
                return this.all();
            } else {
                List<E> list = this.getSelfService().list(param);
                back = JsonBack.success(this.pojoConvertView(list));
            }
        } catch (BusinessException e) {
            back = JsonBack.error(e);
            LOGGER.info("带有参数的查询结果集合异常",back);
        } catch (Exception e) {
            back = JsonBack.error(SYSTEM_CODE_ERROR);
            LOGGER.error("带有参数的查询结果集合异常", e);
        }
        return back;
    }

    /**
     * @author Anson
     * @date 17-3-14
     * @name 带全查询
     * @since 1.0.1
     */
    @RequestMapping("/all")
    public JsonBack<List<V>> all() {
        JsonBack<List<V>> back = null;
        try {
            List<E> list = this.getSelfService().list(null);
            back = JsonBack.success(this.pojoConvertView(list));
        } catch (BusinessException e) {
            back = JsonBack.error(e);
            LOGGER.info("带有参数的查询结果集合异常",back);
        } catch (Exception e) {
            back = JsonBack.error(SYSTEM_CODE_ERROR);
            LOGGER.error("带有参数的查询结果集合异常", e);
        }
        return back;
    }

    /**
     * @param param 带有查询匹配的key的参数集合
     * @require currentPageNo 当前第几也
     * @require maxResult     每页最大值
     * @author Anson
     * @date 17-3-14
     * @name 分页查询, 从第几页开始，每一页的条数
     * @see CriteriaRestrictionsBuilder
     * @since 1.0.1
     */
    @RequestMapping("/page")
    public JsonBack<Pagination<V>> paginationByPageNo(@RequestParam Map<String, Object> param) {
        JsonBack<Pagination<V>> back = null;
        try {
            param = this.convertParams(param);
            int currentPageNo = MapGetUtils.getAndRemoveDigits(param, "currentPageNo");
            int maxResult = MapGetUtils.getAndRemoveDigits(param, "maxResult");
            Pagination<E> pagination = this.getSelfService().pagination(param, currentPageNo, maxResult);
            Pagination<V> voPagination = this.convertPagination(pagination);
            back = JsonBack.success(voPagination);
        } catch (BusinessException e) {
            back = JsonBack.error(e);
            LOGGER.info("[page]分页查询",back);
        } catch (Exception e) {
            back = JsonBack.error(SYSTEM_CODE_ERROR);
            LOGGER.error("[page]分页查询", e);
        }
        return back;
    }


    /**
     * @param param 带有查询匹配的key的参数集合
     * @require start 当前第几个数据开始
     * @require limit     每页最大值
     * @author Anson
     * @date 17-3-14
     * @name 分页查询
     * @see CriteriaRestrictionsBuilder
     * @since 1.0.1
     */
    @RequestMapping("/pageStart")
    public JsonBack<PagingationStart<V>> paginationByStart(@RequestParam Map<String, Object> param) {
        JsonBack<PagingationStart<V>> back = null;
        try {
            param = this.convertParams(param);
            int start = MapGetUtils.getAndRemoveDigits(param, "start");
            int maxResult = MapGetUtils.getAndRemoveDigits(param, "limit");
            PagingationStart<E> pagination = this.getSelfService().paginationStart(param, start, maxResult);
            PagingationStart<V> voPagination = this.convertPaginationStart(pagination);
            back = JsonBack.success(voPagination);
        } catch (BusinessException e) {
            back = JsonBack.error(e);
            LOGGER.info("[pageStart]分页查询",back);
        } catch (Exception e) {
            back = JsonBack.error(SYSTEM_CODE_ERROR);
            LOGGER.error("[pageStart]分页查询", e);
        }
        return back;
    }


    /**
     * @param id 查询主键
     * @author Anson
     * @date 17-3-14
     * @name 查询详细
     * @see CriteriaRestrictionsBuilder
     * @since 1.0.1
     */
    @RequestMapping("/get")
    public JsonBack<V> get(@RequestParam("id") PK id) {
        JsonBack<V> back = null;
        try {
            E E = this.getSelfService().get(id);
            V v = this.newViewVo();
            v = v.view(E);
            back = JsonBack.success(v);
        } catch (BusinessException e) {
            back = JsonBack.error(e);
            LOGGER.info("查询详细={}",back);
        } catch (Exception e) {
            back = JsonBack.error(SYSTEM_CODE_ERROR);
            LOGGER.error("查询详细", e);
        }
        return back;
    }


    /**
     * @param v 新增
     * @author Anson
     * @date 17-3-14
     * @name 新增参数
     * @see CriteriaRestrictionsBuilder
     * @since 1.0.1
     */
    @RequestMapping("/insert")
    public JsonBack<V> insert(@ModelAttribute @Valid V v, BindingResult result) {
        JsonBack<V> back = null;
        try {
            if (result.hasErrors()) {
                //如果没有通过,跳转提示
                JsonBack.throwErrorException(result);
            }
            E E = v.convert();
            this.preInsertHandler(E);
            this.getSelfService().save(E);
            this.postInsertHandler(E);
            V view = this.newViewVo();
            view= view.view(E);
            back = JsonBack.success(view);
        } catch (BusinessException e) {
            back = JsonBack.error(e);
            LOGGER.info("新增失败={}",back);
        } catch (Exception e) {
            back = JsonBack.error(SYSTEM_CODE_ERROR);
            LOGGER.error("新增失败", e);
        }
        return back;
    }


    /**
     * @param v 更新参数
     * @author Anson
     * @date 17-3-14
     * @name 更新
     * @see CriteriaRestrictionsBuilder
     * @since 1.0.1
     */
    @RequestMapping("/update")
    public JsonBack<V> update(@ModelAttribute @Valid V v, BindingResult result) {
        JsonBack<V> back = null;
        try {
            if (result.hasErrors()) {
                //如果没有通过,跳转提示
                JsonBack.throwErrorException(result);
            }
            E E = v.convert();
            if (StringUtils.isEmpty(E.getId())) {
                throw new BusinessException(PARAM_ILLEGAL_ERROR.getCodeStatus(), "更新事务缺少主键");
            }
            this.preUpdateHandler(E);
            this.getSelfService().update(E);
            this.postUpdateHandler(E);
            V view = this.newViewVo();
            view= view.view(E);
            back = JsonBack.success(view);
        } catch (BusinessException e) {
            back = JsonBack.error(e);
            LOGGER.info("更新失败={}",back);
        } catch (Exception e) {
            back = JsonBack.error(SYSTEM_CODE_ERROR);
            LOGGER.error("更新", e);
        }
        return back;
    }

    /**
     * @param id 删除
     * @author Anson
     * @date 17-3-14
     * @name 删除
     * @see CriteriaRestrictionsBuilder
     * @since 1.0.1
     */
    @RequestMapping("/delete")
    public JsonBack<String> delete(@RequestParam("id") PK id) {
        JsonBack<String> back = null;
        try {
            this.preDeleteHandler(id);
            this.getSelfService().deletePK(id);
            this.postDeleteHandler(id);
            back = JsonBack.success(null);
        } catch (BusinessException e) {
            back = JsonBack.error(e);
            LOGGER.info("删除失败={}",back);
        } catch (Exception e) {
            back = JsonBack.error(SYSTEM_CODE_ERROR);
            LOGGER.error("删除", e);
        }
        return back;
    }

    /**
     * 保存前置处理
     *
     * @param e
     * @throws BusinessException
     */
    protected void preInsertHandler(E e) throws BusinessException {

    }

    /**
     * 更新前置接口
     *
     * @param e
     * @throws BusinessException
     */
    protected void preUpdateHandler(E e) throws BusinessException {

    }

    /**
     * 删除前置接口
     *
     * @param id
     * @throws BusinessException
     */
    protected void preDeleteHandler(PK id) throws BusinessException {

    }

    /**
     * 保存后置处理
     *
     * @param e
     * @throws BusinessException
     */
    protected void postInsertHandler(E e) throws BusinessException {

    }

    /**
     * 更新后置接口
     *
     * @param e
     * @throws BusinessException
     */
    protected void postUpdateHandler(E e) throws BusinessException {

    }

    /**
     * 删除后置接口
     *
     * @param id
     * @throws BusinessException
     */
    protected void postDeleteHandler(PK id) throws BusinessException {

    }

    /**
     * @param list pojo集合
     * @author Anson
     * @date 17-4-17
     * @name 转换pojo集合为vo集合
     * @since 1.0.4
     */
    protected List<V> pojoConvertView(List<E> list) {
        if (list == null) {
            return null;
        }
        List<V> datas = new ArrayList<V>();
        V v = null;
        for (E e : list) {
            v = newViewVo();
            if (v == null) {
                continue;
            }
            v = v.view(e);
            datas.add(v);
        }
        return datas;
    }


    /**
     * @param pagination 分页处理pojo
     * @author Anson
     * @date 17-4-17
     * @name 分页处理pojo 的pagination转vo pagination
     * @since 1.0.4
     */
    protected Pagination<V> convertPagination(Pagination<E> pagination) {
        if (pagination == null) {
            return null;
        }
        Pagination<V> vPagination = new Pagination<V>();
        try {
            BeanUtils.copyProperties(pagination, vPagination, "list");
            List<E> list = pagination.getList();
            List<V> datas = this.pojoConvertView(list);
            vPagination.setList(datas);
        } catch (BeansException e) {
            LOGGER.error("Pagination : pagination -> vPagination bean拷贝异常, pagination={}", pagination, e);
        }
        return vPagination;
    }

    /**
     * @param pagination ext分页处理pojo
     * @author Anson
     * @date 17-4-17
     * @name 分页处理 pojo 的pagination转vo pagination
     * @since 1.0.4
     */
    protected PagingationStart<V> convertPaginationStart(PagingationStart<E> pagination) {
        if (pagination == null) {
            return null;
        }
        PagingationStart<V> vPagination = new PagingationStart<V>();
        try {
            BeanUtils.copyProperties(pagination, vPagination, "list");
            List<E> list = pagination.getList();
            List<V> datas = this.pojoConvertView(list);
            vPagination.setList(datas);
        } catch (BeansException e) {
            LOGGER.error("PagingationStart : pagination -> vPagination bean拷贝异常, pagination={}", pagination, e);
        }
        return vPagination;
    }

}
